package com.nw.dsl4j.runtime.parser;

import java.util.ArrayList;
import java.util.List;

import org.antlr.runtime.CharStream;
import org.antlr.runtime.CommonToken;
import org.antlr.runtime.ParserRuleReturnScope;
import org.apache.commons.beanutils.BeanUtils;

import com.nw.dsl4j.runtime.converters.Converter;
import com.nw.dsl4j.runtime.converters.ConverterManager;
import com.nw.dsl4j.runtime.resolve.ResolutionTask;

public class AntlrParserContext implements Dsl4jParserContext {
	
	private ConverterManager converterManager = new ConverterManager();
	private CharStream input;
	private List<ResolutionTask> resolutionTasks = new ArrayList<ResolutionTask>();

	public void applyLocationToObject(Object locationObject, Object domainObject) {
		if (!(domainObject instanceof com.nw.dsl4j.runtime.adapter.Adaptable)){
			return;
		}
		com.nw.dsl4j.runtime.parser.LocationSupport locationSupport = ((com.nw.dsl4j.runtime.adapter.Adaptable) domainObject).getAdapter(com.nw.dsl4j.runtime.parser.LocationSupport.class);
		if (locationObject instanceof CommonToken) {
			CommonToken ct = (CommonToken)locationObject;
			locationSupport.setStartIndex(ct.getStartIndex());
			locationSupport.setEndIndex(ct.getStopIndex());
			locationSupport.setText(ct.getText());
		} else if (locationObject instanceof ParserRuleReturnScope){
			ParserRuleReturnScope rrs = (ParserRuleReturnScope)locationObject;
			locationSupport.setStartIndex(((CommonToken) rrs.start).getStartIndex());
			locationSupport.setEndIndex(((CommonToken) rrs.stop).getStopIndex());
			locationSupport.setText(input.substring(locationSupport.getStartIndex(),locationSupport.getEndIndex()));
		} else {
			throw new IllegalStateException(locationObject.getClass() + " is not supported");
		}
	}

	public Object extractKey(Object o, String mapKeyField) {
		try {
			return BeanUtils.getProperty(o, mapKeyField);
		} catch (Exception e) {
			throw new IllegalStateException(e);
		}
	}

	public Converter getConverter(String name) {
		return getConverterManager().getConverter(name);
	}
	
	public ConverterManager getConverterManager() {
		return converterManager;
	}

	public void setConverterManager(ConverterManager converterManager) {
		this.converterManager = converterManager;
	}

	public void setInput(CharStream input) {
		this.input = input;
	}

	public void addResolutionTaks(ResolutionTask resolutionTask) {
		resolutionTasks.add(resolutionTask);
	}

	public List<ResolutionTask> getResolutionTasks() {
		return resolutionTasks;
	}

	public void addResolutionTask(Object container, Object reference, String field) {
		addResolutionTaks(new ResolutionTask(container, reference, field));
	}
}
